package com.command.center.pucms.common.util;

import cn.hutool.crypto.digest.BCrypt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.command.center.pucms.common.constant.Constant;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;

/**
 * @author zlb
 * @since 2021-04-26
 */
@Slf4j
public class SimpleJwtUtil {


    private SimpleJwtUtil() {

    }

    /**
     * 校验token是否正确  参考sign生成规则
     *
     * @param token 密钥
     * @return 是否正确
     */
    public static boolean verify(String token) throws Exception {
        Algorithm algorithm = Algorithm.HMAC256(Constant.TOKEN_SECRET);
        JWTVerifier verifier = JWT.require(algorithm).build();
        DecodedJWT decodedJWT = verifier.verify(token);
        log.info("认证通过：");
        log.info("userName: " + decodedJWT.getClaim(Constant.TOKEN_USER_NAME).asString());
        log.info("过期时间：      " + decodedJWT.getExpiresAt());
        return true;
    }

    /**
     * todo
     * 生成签名,包含过期时间，包含角色及权限信息
     *
     * @param secret 秘钥和密码相关  保证修改后之前的签名失效
     * @return 加密的token
     */
    public static boolean verify(String token, String secret, Long currentTime) {
        try {
            try {
                Algorithm algorithm = Algorithm.HMAC256(Constant.TOKEN_SECRET + secret);
                String userName = SimpleJwtUtil.getUserName(token);
                JWTVerifier verifier = JWT.require(algorithm)
                        .withClaim(Constant.TOKEN_USER_NAME, userName)

                        .build();
                DecodedJWT decodedJWT = verifier.verify(token);
                log.info("认证通过：");
                log.info("userName: " + decodedJWT.getClaim(Constant.TOKEN_USER_NAME).asString());
                log.info("过期时间：      " + decodedJWT.getExpiresAt());
                return true;
            } catch (Exception e) {
                log.error("校验token失败：", e);
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * 获得token中的信息
     *
     * @return token中包含的用户名
     */
    public static String getUserName(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(Constant.TOKEN_USER_NAME).asString();
        } catch (Exception e) {
            log.error("获取token中的用户名失败：", e);
            return null;
        }
    }

    /**
     * 获得token中的信息
     *
     * @return token中包含的过期时间戳
     */
    public static Long getExpireTime(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            //exp 为官方定义字段  所有jwtToken都有 详情参考jwt生成规则
            return jwt.getClaim("exp").asLong();
        } catch (Exception e) {
            log.error("获取token中的过期时间戳失败：", e);
            return null;
        }
    }

    /**
     * 获得token中的信息
     *
     * @return token中包含的当前时间戳
     */
    public static Long getCurrentTime(String token) {
        try {
            DecodedJWT decodedJWT = JWT.decode(token);
            return decodedJWT.getClaim("currentTime").asLong();

        } catch (JWTCreationException e) {
            log.error("获取token中的当前时间戳失败：", e);
            return null;
        }
    }


    /**
     * 生成签名,包含过期时间
     *
     * @param userName    用户名
     * @param currentTime 当前时间戳
     * @return 加密的token
     */
    public static String sign(String userName, Long currentTime) {
        try {
            Date expireAt = new Date(currentTime + Constant.EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(Constant.TOKEN_SECRET);
            return JWT.create()
                    .withClaim(Constant.TOKEN_USER_NAME, userName)
                    .withClaim(Constant.CURRENT_TIME,currentTime)
                    .withExpiresAt(expireAt)
                    .sign(algorithm);
        } catch (Exception e) {
            log.error("生成签名失败：", e);
            return null;
        }
    }


    /**
     * 生成签名,包含过期时间
     *
     * @param userName    用户名
     * @param secret      秘钥与密码有关  保证修改后之前的签名失效
     * @param currentTime 当前时间戳
     * @return 加密的token
     */
    public static String sign(String userName, String secret, Long currentTime) {
        try {
            Date expireAt = new Date(currentTime + Constant.EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(Constant.TOKEN_SECRET + secret);
            return JWT.create()
                    .withClaim(Constant.TOKEN_USER_NAME, userName)
                    .withExpiresAt(expireAt)
                    .sign(algorithm);
        } catch (Exception e) {
            log.error("生成签名失败：", e);
            return null;
        }
    }


    /**
     * 生成签名,包含过期时间，包含角色及权限信息
     *
     * @param userName    用户名
     * @param secret      秘钥和密码相关  保证修改后之前的签名失效
     * @param expireTime  过期时间
     * @param roles       角色信息  该用户的所有角色
     * @param permissions 权限信息  该用户拥有的所有权限
     * @return 加密的token
     */
    public static String sign(String userName, String secret, long expireTime, List<String> roles, List<String> permissions) {
        try {
            Date date = new Date(System.currentTimeMillis() + expireTime);
            Algorithm algorithm = Algorithm.HMAC256(Constant.TOKEN_SECRET + secret);
            return JWT.create()
                    .withClaim(Constant.TOKEN_USER_NAME, userName)
                    .withArrayClaim(Constant.TOKEN_USER_ROLE, roles.toArray(new String[roles.size()]))
                    .withArrayClaim(Constant.TOKEN_USER_PERMISSION, permissions.toArray(new String[permissions.size()]))
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            log.error("生成签名失败：", e);
            return null;
        }
    }

    public static void main(String[] args) {
        String userName = "zlb";
        String passWord = "123456";
        System.out.println(BCrypt.hashpw(passWord, BCrypt.gensalt()));
    }
}
